﻿// -----------------------------------------------------------------------
// <copyright file="PlaceableGameComponent.cs" company="None">
// </copyright>
// -----------------------------------------------------------------------
namespace Cubezicles
{
    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Linq;
    using Microsoft.Xna.Framework;
    using Microsoft.Xna.Framework.Graphics;

    // Game component with convenience accessor for our global Game1 type
    public class DrawableGame1Component : DrawableGameComponent
    {
        public DrawableGame1Component(Game1 game) : base(game) { }

        public Game1 Game1 { get { return (Game1)Game; } }
    }

    /// <summary>
    /// A DrawableGameComponent that also knows its position
    /// </summary>
    public class PlaceableGameComponent : DrawableGame1Component
    {
        // Properties to be used in item manager or hiring manager
        public String name = "", tagline = "";
        public int price = 0;
        public Texture2D avatar;

        // Get the Game1 object stored by the base class
        private Game1 game1 { get { return (Game1)Game; } }

        // Position of the object in world coordinates
        private Vector3 _position = new Vector3();
        public Vector3 Position
        {
            get { return _position; }
            set 
            {
                _position = value;
                if (PGCModel != null)
                {
                    BoundingSphere = CalculateBoundingSphere();
                }
            }
        }

        public void MoveLeft()
        {
            Position = new Vector3(Position.X-.5f, Position.Y, Position.Z );
        }
        public void MoveRight()
        {
            Position = new Vector3(Position.X + .5f, Position.Y, Position.Z);
        }

        public Quaternion Orientation { get; set; }

        public Vector3 Scaling { get; set; }

        public Model PGCModel { get; set; }

        public bool IsSelected
        {
            get { return Game1.CurrentSelectedObject == this; }
        }

        private string modelName { get; set; } //.........

        //---fuelcell option.......... for 3d choosing/selecting 3d object
        public BoundingSphere BoundingSphere { get; set; }

        // Get a transformation matrix for drawing (translation or transformation? or same thing? ******)
        public Matrix ModelMatrix 
        {
            get
            {
                // Applies translation THEN rotation THEN scaling
                return Matrix.CreateScale(Scaling) *
                       Matrix.CreateFromQuaternion(Orientation) *
                       Matrix.CreateTranslation(Position);
            }
        }

        // Initialize the object with the given position and a default orientation
        // and scale
        public PlaceableGameComponent(Game1 game, Vector3 position, string modelname) : base(game) 
        {
            Position = position;
            Orientation = Quaternion.Identity;
            Scaling = Vector3.One * 3; // Blow up to 3x the loaded size

            modelName = modelname;
        }

        protected override void LoadContent()
        {
            PGCModel = LoadModel(modelName);
            BoundingSphere = CalculateBoundingSphere();
        }

        //-- from fuelcell sample code --//
        // calculate the overall bounding sphere for the entire object
        protected BoundingSphere CalculateBoundingSphere()
        {
            // Is there ever a situation where a loaded model has no meshes?
            // That doesn't make a lot of sense.
            Debug.Assert(PGCModel.Meshes.Count > 0);

            var spheres = Enumerable.Select(PGCModel.Meshes, x => x.BoundingSphere);

            BoundingSphere mergedSphere = Enumerable.Aggregate(spheres,
                BoundingSphere.CreateMerged);

            // Move the center of the bounding sphere with the object
            mergedSphere.Center = Vector3.Transform(mergedSphere.Center, ModelMatrix);

            // assume uniform scaling because we're lazy
            mergedSphere.Radius *= Scaling.X;

            return mergedSphere;
        }

        /// <summary>
        /// Draw the placeable game component, show selected objects with a teal-ish aura
        /// </summary>
        public override void Draw(GameTime gameTime)
        {
            // Don't try to alpha-blend this object
            GraphicsDevice.BlendState = BlendState.AlphaBlend;

            // Enable backface culling
            GraphicsDevice.DepthStencilState = DepthStencilState.Default;

            // This does some fancy thing to turn textures back on
            GraphicsDevice.SamplerStates[0] = SamplerState.LinearWrap;

            var camera = Game.Services.GetService<ICamera>();

            // Show selected object with a teal-ish aura
            if(IsSelected)
            {
                PGCModel.ForEachEffect(ef => { ef.EmissiveColor = new Vector3(0.0f, 0.4f, 0.4f); });
            }

            PGCModel.Draw(ModelMatrix, camera.ViewMatrix, camera.ProjectionMatrix);

            // Return highlight to zero for next time
            if (IsSelected)
            {
                PGCModel.ForEachEffect(ef => { ef.EmissiveColor = Vector3.Zero; });
            }

            //Draw pathfinder graph
            game1.drawGraph(ModelMatrix, camera);

            base.Draw(gameTime);
        }

        // Rotate 90 degrees clockwise... well actually not sure if CW or CCW
        public void Rotate90CW()
        {
           Orientation *= Quaternion.CreateFromAxisAngle(new Vector3(0, 1, 0), MathHelper.PiOver2);
        }

        /// <summary>
        /// Function to make sure that models are only loaded once.
        /// </summary>
        static Dictionary<string, Model> models = new Dictionary<string, Model>();
        protected Model LoadModel(string name)
        {
            if (!models.ContainsKey(name))
            {
                models[name] = Game.Content.Load<Model>(name); // ***todo: accessviolationexception unhandled
                models[name].ForEachEffect(effect => effect.EnableDefaultLighting());
            }

            return models[name];
        }
    }
}
